﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Net;

namespace RenjianImageViewer.ViewModel
{
    class ImageViewModel : DependencyObject
    {
        private static Dictionary<long, WeakReference> s_thumbnailCache = new Dictionary<long, WeakReference>();

        public static readonly DependencyProperty IsLocalProperty = DependencyProperty.Register(
            "IsLocal", typeof(bool), typeof(ImageViewModel), new FrameworkPropertyMetadata(false));
        public static readonly DependencyProperty PercentageProperty = DependencyProperty.Register(
            "Percentage", typeof(double), typeof(ImageViewModel), new PropertyMetadata(0d, OnPercentageChanged));

        public bool IsLocal
        {
            get { return (bool)GetValue(IsLocalProperty); }
            set { SetValue(IsLocalProperty, value); }
        }
        public double Percentage
        {
            get { return (double)this.GetValue(PercentageProperty); }
            set { this.SetValue(PercentageProperty, value); }
        }

        private static void OnPercentageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ImageViewModel ivm = d as ImageViewModel;
            var tmp = ivm.DownloadStreamPercentageChanged;
            if (null != tmp)
            {
                tmp(d, new PercentageChangedEventArgs { Percentage = (double)e.NewValue });
            }
        }

        private string statusString;
        private DataModel.StatusModel statusModel;
        //private BitmapImage thumbnailCache = null;
        private long statusID;
        private string imageUrl;
        private Stream streamData;

        public event EventHandler DownloadStreamCompleted;
        public event EventHandler<PercentageChangedEventArgs> DownloadStreamPercentageChanged;

        public string ThumbnailUrl { get; set; }
        public string TimeTag { get; set; }
        public bool DisplayTimeTag
        {
            get
            {
                return !string.IsNullOrEmpty(TimeTag);
            }
        }

        public long StatusID
        {
            get
            {
                return statusID;
            }
            set
            {
                statusID = value;
                string[] files = Directory.GetFiles(@"c:\\rensea\", string.Format("{0}.*", statusID.ToString()));
                if (files != null && files.Length > 0)
                {
                    imageUrl = files[0];
                    IsLocal = true;
                }
            }
        }
        public string ImageUrl
        {
            get
            {
                return imageUrl;
            }
            set
            {
                if (!IsLocal)
                {
                    imageUrl = value;
                }
            }
        }

        public DataModel.StatusModel StatusModel
        {
            get
            {
                if (null == statusModel)
                {
                    statusModel = new DataModel.StatusModel(statusString);
                }
                return statusModel;
            }
        }

        public BitmapImage Thumbnail
        {
            get
            {
                if (!s_thumbnailCache.ContainsKey(statusID) || s_thumbnailCache[statusID].Target == null)
                {
                    BitmapImage image = new BitmapImage();
                    s_thumbnailCache[statusID] = new WeakReference(image, false);
                    image.BeginInit();
                    image.CacheOption = BitmapCacheOption.OnDemand;
                    image.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
                    image.DownloadFailed += image_DownloadFailed;
                    image.UriSource = new Uri(ThumbnailUrl);
                    image.EndInit();
                }
                return s_thumbnailCache[statusID].Target as BitmapImage;
            }
        }

        public FrameworkElement Image
        {
            get
            {
                FrameworkElement result = null;
                if (null == streamData)
                {
                    DownloadStream();
                }

                if (string.Compare(".gif", Path.GetExtension(ImageUrl), true) == 0)
                {
                    //MediaElement media = new MediaElement();
                    //media.Stretch = System.Windows.Media.Stretch.Uniform;
                    //media.StretchDirection = StretchDirection.DownOnly;

                    //media.BeginInit();
                    //media.LoadedBehavior = MediaState.Play;
                    //media.Source = new Uri(ImageUrl);
                    //media.EndInit();

                    GIFImageControl g = new GIFImageControl();
                    g.Stretch = System.Windows.Media.Stretch.Uniform;
                    g.StretchDirection = StretchDirection.Both;
                    g.AnimatedImageControl(streamData);
                    result = g;
                }
                else
                {
                    System.Windows.Controls.Image imageControl = new System.Windows.Controls.Image();
                    BitmapImage image = new BitmapImage();
                    image.BeginInit();
                    image.UriCachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.CacheIfAvailable);
                    image.CacheOption = BitmapCacheOption.OnDemand;
                    image.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
                    image.DownloadFailed += image_DownloadFailed;
                    //image.UriSource = new Uri(ImageUrl);
                    image.StreamSource = streamData;
                    image.EndInit();
                    if (!image.IsDownloading)
                    {
                        imageControl.MaxWidth = image.PixelWidth;
                        imageControl.MaxHeight = image.PixelHeight;
                    }
                    try
                    {
                        imageControl.Stretch = System.Windows.Media.Stretch.Uniform;
                        imageControl.StretchDirection = StretchDirection.Both;
                        imageControl.Source = image;
                        result = imageControl;
                    }
                    catch
                    {
                        return null;
                    }
                }
                return result;
            }
        }

        void image_DownloadFailed(object sender, System.Windows.Media.ExceptionEventArgs e)
        {
            string url = sender.ToString();
            if (url != ImageUrl)
            {
                ThumbnailUrl = ImageUrl;
                s_thumbnailCache.Remove(statusID);
            }
            else
            {
                System.Windows.MessageBox.Show(e.ErrorException.Message + Environment.NewLine +
                    "url:" + sender.ToString());
            }
        }

        public ImageViewModel(string statusString)
        {
            this.statusString = statusString;
        }

        public void DownloadStream()
        {
            if (IsLocal)
            {
                streamData = File.OpenRead(ImageUrl);
            }
            else
            {
                using (WebClient wc = new WebClient())
                {
                    byte[] s = wc.DownloadData(ImageUrl);
                    streamData = new MemoryStream(s);
                }
            }
        }

        public void DownloadStreamAsync()
        {
            if (IsLocal)
            {
                streamData = File.OpenRead(ImageUrl);
                var tmp = DownloadStreamCompleted;
                if (null != tmp)
                {
                    tmp(this, null);
                }
            }
            else if (Percentage == 0)
            {
                WebClient wc = new WebClient();
                //Hack to remove watermark
                wc.Headers.Add(HttpRequestHeader.Referer, "http://renjian.com/home");
                wc.DownloadProgressChanged += (s, e) => Percentage = e.ProgressPercentage;
                wc.DownloadDataCompleted += (s, e) =>
                    {
                        streamData = new MemoryStream(e.Result);
                        wc.Dispose();
                        var tmp = DownloadStreamCompleted;
                        if (null != tmp)
                        {
                            tmp(this, e);
                        }
                    };
                wc.DownloadDataAsync(new Uri(ImageUrl), wc);
            }
        }
    }

    public class GIFImageControl : System.Windows.Controls.Image
    {
        delegate void OnFrameChangedDelegate();
        private Bitmap m_Bitmap;
        BitmapSource bitmapSource;

        public void AnimatedImageControl(Stream stream)
        {
            m_Bitmap = (Bitmap)System.Drawing.Image.FromStream(stream);
            Width = m_Bitmap.Width;
            Height = m_Bitmap.Height;
            ImageAnimator.Animate(m_Bitmap, OnFrameChanged);
            bitmapSource = GetBitmapSource();
            Source = bitmapSource;
        }


        private void OnFrameChanged(object sender, EventArgs e)
        {

            Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                   new OnFrameChangedDelegate(OnFrameChangedInMainThread));

        }

        private void OnFrameChangedInMainThread()
        {
            try
            {
                ImageAnimator.UpdateFrames();
                if (bitmapSource != null)
                    bitmapSource.Freeze();
                bitmapSource = GetBitmapSource();
                Source = bitmapSource;
                InvalidateVisual();
            }
            catch { }
        }

        //private static bool loaded;
        private BitmapSource GetBitmapSource()
        {
            IntPtr inptr = m_Bitmap.GetHbitmap();
            bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(
                inptr, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            DeleteObject(inptr);
            return bitmapSource;
        }

        [DllImport("gdi32")]
        static extern int DeleteObject(IntPtr o);
    }

    class PercentageChangedEventArgs : EventArgs
    {
        public double Percentage;
    }
}